package lt.marsrutai.mobile.android.fragment;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;

import lt.marsrutai.mobile.android.AppContext;
import lt.marsrutai.mobile.android.R;
import lt.marsrutai.mobile.android.activity.intent.NearestRoutesIntentHolder;
import lt.marsrutai.mobile.android.activity.intent.StopSearchIntentHolder;
import lt.marsrutai.mobile.android.adapter.StopIndexedAdapter;
import lt.marsrutai.mobile.android.bean.StopSearchCriteria;
import lt.marsrutai.mobile.android.content.StopSearchRecentSuggestionsProvider;
import lt.marsrutai.mobile.android.exception.DataAccessException;
import lt.marsrutai.mobile.android.manager.ActivityManager;
import lt.marsrutai.mobile.android.manager.StopSearchPreferenceManager;
import lt.marsrutai.mobile.android.model.Stop;
import lt.marsrutai.mobile.android.service.impl.LocationProviderImpl.GetLocationTask;
import lt.marsrutai.mobile.android.service.impl.LocationProviderImpl.PostExecute;
import lt.marsrutai.mobile.android.util.PreferenceUtils;
import lt.marsrutai.mobile.android.util.StringUtils;
import android.location.Location;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.TextView;

import com.actionbarsherlock.app.SherlockListFragment;

public class StopSearchFragment extends SherlockListFragment {

    private GetLocationTask getLocationTask;
    
    private ActivityManager manager;

    private List<Stop> stops;
    private StopIndexedAdapter adapter;

    private String scopeFolder;
    
    @Override
    public void onStart() {
        super.onStart();
        
        // Activity visible - start listening for location updates
        AppContext.getLocationProvider().start();
    }

    @Override
    public void onStop() {
        super.onStart();
        
        // Activity hidden - stop listening for location updates
        AppContext.getLocationProvider().stop();
    }
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.list_fragment, null);
        TextView emptyText = (TextView) view.findViewById(android.R.id.empty);
        emptyText.setText(R.string.stop_search_not_found);

        return view;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        
        // Start listening for location updates
        AppContext.getLocationProvider().start();

        manager = new ActivityManager(getActivity());
        manager.showDownloadLoadingBar();

        receiveItemData();

        adapter = new StopIndexedAdapter(getActivity(), scopeFolder);
        setListAdapter(adapter);

        downloadData();
    }

    @Override
    public void onListItemClick(ListView l, View v, int position, long id) {
        sendItemData(position);
    }

    private void receiveItemData() {
        StopSearchIntentHolder intentHolder = getIntentHolder();
        scopeFolder = intentHolder.getScopeFolder();
    }

    private StopSearchIntentHolder getIntentHolder() {
        return new StopSearchIntentHolder(getArguments());
    }

    private void sendItemData(int i) {
        Stop stop = adapter.getItem(i);
        NearestRoutesIntentHolder intentHolder = new NearestRoutesIntentHolder(getActivity());
        intentHolder.setScopeFolder(scopeFolder);
        intentHolder.setStopName(stop.getName());
        intentHolder.setStopFullName(stop.getFullName());
        intentHolder.setStopId(stop.getId());
        intentHolder.setStopDirectionName(stop.getDirectionName());
        startActivity(intentHolder.getIntent());
    }

    private void downloadData() {
        getLocationTask = (GetLocationTask) new GetLocationTask(getActivity(), new PostExecute() {

            @Override
            public void handle(Location result, String errorMessage) {
                if (result == null) {
                    TextView emptyText = (TextView) getActivity().findViewById(android.R.id.empty);
                    emptyText.setText(errorMessage);
                }
            }
        });
        
        Runnable downloadTask = new Runnable() {
            
            @Override
            public void run() {
                getStops(scopeFolder);
            }
        };

        Thread thread = new Thread(downloadTask);
        thread.start();
    }

    private void getStops(String scopeFolder) {
        try {
            String constraint = getIntentHolder().getQuery();
            if (StringUtils.equals(constraint, StopSearchRecentSuggestionsProvider.QUERY_CLOSEST_STOPS)) {
                Location location = getLocation(getLocationTask);

                if (location != null) {
                    int searchRadius = PreferenceUtils.<Integer> getPreferenceValue(getActivity(),
                            StopSearchPreferenceManager.KEY_NEARBY_STOP_RADIUS);
                    stops = AppContext.getDataService().getStops(scopeFolder, true, null, location.getLatitude(), location.getLongitude(),
                            (double) searchRadius / 1000);
                }
                else {
                    stops = Collections.emptyList();
                }
            }
            else {
                stops = AppContext.getDataService().getStops(scopeFolder, true, constraint, null, null, null);
            }
        }
        catch (DataAccessException e) {
            manager.runOnUiThread(manager.errorRes);
            return;
        }
        manager.runOnUiThread(returnRes);
    }
    
    protected Location getLocation(final GetLocationTask task) {
        Location location = null;
        
        // Execute on UI thread
        getActivity().runOnUiThread(new Runnable() {
            
            @Override
            public void run() {
                task.execute();
            }
        });
        
        // Block and wait for result
        try {
            location = task.get();
        }
        catch (InterruptedException e) {}
        catch (ExecutionException e) {}
        catch (CancellationException e) {}
        
        return location;
    }

    private final Runnable returnRes = new Runnable() {

        @Override
        public void run() {
            if (stops != null && stops.size() > 0) {
                for (int i = 0; i < stops.size(); i++) {
                    adapter.add(stops.get(i));
                }
            }

            manager.dismissDownloadLoadingBar();

            adapter.setOriginalValues(stops);
            adapter.initIndexer();

            // Perform highlighting
            StopSearchCriteria criteria = new StopSearchCriteria();
            criteria.setQuery(getIntentHolder().getQuery());
            filterResults(criteria);
        }
    };

    private void filterResults(StopSearchCriteria criteria) {
        adapter.setSearchCriteria(criteria);
        // No constraint is necessary - filter should use provided search
        // criteria
        adapter.getFilter().filter(null);
    }

    public void searchAgain(String query) {
        getArguments().putString(StopSearchIntentHolder.QUERY, query);
        adapter.clear();
        manager.showDownloadLoadingBar();
        downloadData();
    }
}
